from typing import List, Dict, Any, Optional
from .parser import ASTNode, ASTNodeType
from .catalog import Catalog, TableSchema, ColumnSchema
from .lexer import TokenType

import logging

# 统一日志配置，便于调试与性能分析
logger = logging.getLogger("SemanticAnalyzer")
logger.setLevel(logging.INFO)  # 可根据需要调整日志级别

class SemanticError(Exception):
    """
    语义分析阶段的统一异常类型。
    包含AST节点信息，便于定位错误源。
    错误输出格式：[错误类型, 位置, 原因]
    """
    def __init__(self, message, node=None, error_type="SEMANTIC_ERROR"):
        super().__init__(message)
        self.node = node
        self.error_type = error_type
        self.message = message
        # 从节点获取位置信息
        if node and hasattr(node, 'line') and hasattr(node, 'column'):
            self.line = node.line
            self.column = node.column
        else:
            self.line = 0
            self.column = 0
    
    def to_dict(self):
        """输出标准错误格式"""
        return {
            "error_type": self.error_type,
            "position": f"line {self.line}, column {self.column}",
            "reason": self.message
        }

class SemanticAnalyzer:
    """
    SQL语义分析器。
    负责对AST进行逐条语义校验，确保SQL语句的结构和引用合法。
    支持CREATE/INSERT/SELECT/DELETE等基本语句。
    设计决策：
      - 采用逐节点分派分析，便于扩展新语句类型。
      - 通过Catalog接口获取表和列信息，解耦元数据管理。
      - 支持批量语句分析，便于后续批量优化。
    """

    def __init__(self, catalog: Catalog):
        self.catalog = catalog
        self.current_table: Optional[TableSchema] = None

    def analyze(self, ast_nodes: List[ASTNode]):
        """
        入口：对AST节点列表进行语义分析。
        支持批量语句，便于批量优化和资源评估。
        """
        for node in ast_nodes:
            try:
                self.analyze_statement(node)
            except SemanticError as e:
                logger.error(f"Semantic error: {e} (node: {getattr(e, 'node', None)})")
                raise

    def analyze_statement(self, node: ASTNode):
        """
        根据AST节点类型分派到具体分析方法。
        可扩展支持更多SQL语句类型。
        """
        if node.node_type == ASTNodeType.CREATE_TABLE:
            self.analyze_create_table(node)
        elif node.node_type == ASTNodeType.INSERT:
            self.analyze_insert(node)
        elif node.node_type == ASTNodeType.SELECT:
            self.analyze_select(node)
        elif node.node_type == ASTNodeType.DELETE:
            self.analyze_delete(node)
        elif node.node_type == ASTNodeType.CREATE_DATABASE:
            # CREATE DATABASE 语句无需表级校验，直接通过
            logger.info(f"CREATE DATABASE '{node.value}' checked (no-op for semantic)")
        elif node.node_type == ASTNodeType.USE_DATABASE:
            # USE DATABASE 语句无需表级校验，直接通过
            logger.info(f"USE DATABASE '{node.value}' checked (no-op for semantic)")
        else:
            raise SemanticError(f"Unknown statement type: {node.node_type}", node)

    def analyze_create_table(self, node: ASTNode):
        """
        校验CREATE TABLE语句的表名唯一性、列名唯一性和类型合法性。
        支持VARCHAR(n)类型。
        """
        table_name = node.value
        if table_name in self.catalog.tables:
            raise SemanticError(f"Table '{table_name}' already exists", node)

        columns = []
        col_names = set()
        for col_def in node.children:
            col_name = col_def.value["name"]
            col_type = col_def.value["type"]
            col_length = col_def.value.get("length")

            # 检查列名唯一性
            if col_name in col_names:
                raise SemanticError(f"Duplicate column name '{col_name}'", col_def)
            col_names.add(col_name)

            # 检查类型合法性
            if col_type not in (TokenType.INT, TokenType.VARCHAR):
                raise SemanticError(f"Unsupported column type '{col_type}'", col_def)

            columns.append(ColumnSchema(col_name, col_type, col_length))

        # 注册表结构到目录
        self.catalog.create_table(table_name, columns)
        logger.info(f"Table '{table_name}' created with columns: {columns}")

    def analyze_insert(self, node: ASTNode):
        """
        校验INSERT语句的表存在性、列存在性、值数量与类型匹配。
        支持省略列名时自动补全。
        """
        table_name = node.value
        if table_name not in self.catalog.tables:
            raise SemanticError(f"Table '{table_name}' does not exist", node)

        table_schema = self.catalog.tables[table_name]
        self.current_table = table_schema

        # 分离列引用和值
        column_refs = []
        values = []
        for child in node.children:
            if child.node_type == ASTNodeType.COLUMN_REF:
                column_refs.append(child)
            elif child.node_type == ASTNodeType.VALUE:
                values.append(child)

        # 若未指定列名，默认所有列
        if not column_refs:
            column_refs = [ASTNode(ASTNodeType.COLUMN_REF, value=col.name) for col in table_schema.columns]

        # 列存在性校验
        for col_ref in column_refs:
            col_name = col_ref.value
            if not any(col.name == col_name for col in table_schema.columns):
                raise SemanticError(f"Column '{col_name}' does not exist in table '{table_name}'", col_ref)

        # 值数量匹配校验
        if len(values) != len(column_refs):
            raise SemanticError(f"Number of values ({len(values)}) does not match number of columns ({len(column_refs)})", node)

        # 类型匹配校验
        for i, (col_ref, value) in enumerate(zip(column_refs, values)):
            col_name = col_ref.value
            column = next(col for col in table_schema.columns if col.name == col_name)
            if column.type == TokenType.INT and not isinstance(value.value, int):
                raise SemanticError(f"Type mismatch: expected INT for column '{col_name}', got {type(value.value).__name__}", value)
            elif column.type == TokenType.VARCHAR and not isinstance(value.value, str):
                raise SemanticError(f"Type mismatch: expected VARCHAR for column '{col_name}', got {type(value.value).__name__}", value)

    def analyze_select(self, node: ASTNode):
        """
        校验SELECT语句的表存在性、列存在性、WHERE子句表达式合法性。
        支持SELECT *语法。
        支持后续扩展多表、子查询等。
        """
        table_ref = None
        column_refs = []
        where_clause = None
        has_star = False

        for child in node.children:
            if child.node_type == ASTNodeType.TABLE_REF:
                table_ref = child
            elif child.node_type == ASTNodeType.COLUMN_REF:
                column_refs.append(child)
            elif child.node_type == ASTNodeType.BINARY_OP:
                where_clause = child
            elif child.node_type == ASTNodeType.STAR:
                has_star = True

        if not table_ref:
            raise SemanticError("Missing table reference in SELECT statement", node)

        table_name = table_ref.value
        if table_name not in self.catalog.tables:
            raise SemanticError(f"Table '{table_name}' does not exist", table_ref)

        table_schema = self.catalog.tables[table_name]
        self.current_table = table_schema

        # SELECT * 语法：自动补全所有列
        if has_star:
            column_refs = [ASTNode(ASTNodeType.COLUMN_REF, value=col.name) for col in table_schema.columns]

        # 列存在性校验
        for col_ref in column_refs:
            col_name = col_ref.value
            if not any(col.name == col_name for col in table_schema.columns):
                raise SemanticError(f"Column '{col_name}' does not exist in table '{table_name}'", col_ref)

        # WHERE子句表达式递归校验
        if where_clause:
            self.analyze_expression(where_clause)

    def analyze_delete(self, node: ASTNode):
        """
        校验DELETE语句的表存在性、WHERE子句表达式合法性。
        """
        table_ref = None
        where_clause = None

        for child in node.children:
            if child.node_type == ASTNodeType.TABLE_REF:
                table_ref = child
            elif child.node_type == ASTNodeType.BINARY_OP:
                where_clause = child

        if not table_ref:
            raise SemanticError("Missing table reference in DELETE statement", node)

        table_name = table_ref.value
        if table_name not in self.catalog.tables:
            raise SemanticError(f"Table '{table_name}' does not exist", table_ref)

        table_schema = self.catalog.tables[table_name]
        self.current_table = table_schema

        # WHERE子句表达式递归校验
        if where_clause:
            self.analyze_expression(where_clause)

    def analyze_expression(self, node: ASTNode):
        """
        递归校验表达式节点（如WHERE子句）。
        检查列引用合法性，支持后续扩展复杂表达式。
        """
        if node.node_type == ASTNodeType.BINARY_OP:
            left, right = node.children

            # 左操作数为列引用时校验
            if left.node_type == ASTNodeType.COLUMN_REF:
                col_name = left.value
                if not any(col.name == col_name for col in self.current_table.columns):
                    raise SemanticError(f"Column '{col_name}' does not exist in table '{self.current_table.name}'", left)

            # 右操作数为列引用时校验
            if right.node_type == ASTNodeType.COLUMN_REF:
                col_name = right.value
                if not any(col.name == col_name for col in self.current_table.columns):
                    raise SemanticError(f"Column '{col_name}' does not exist in table '{self.current_table.name}'", right)

            # 递归分析子表达式
            self.analyze_expression(left)
            self.analyze_expression(right)

        elif node.node_type == ASTNodeType.COLUMN_REF:
            col_name = node.value
            if not any(col.name == col_name for col in self.current_table.columns):
                raise SemanticError(f"Column '{col_name}' does not exist in table '{self.current_table.name}'", node)
